"""
TodoLog Service层（业务逻辑层）
负责封装Todo日志相关的业务逻辑，依赖DAO层进行数据访问，所有方法返回格式统一为 (bool, result)
- 成功：(True, 结果数据/None)
- 失败：(False, 错误信息字符串)
"""
from app.Dao.TodoDao.TodoDao import TodoDAO
from app.Dao.TodoDao.TodoLogDao import TodoLogDAO
from datetime import datetime
import re

from app.Utils.Decorator.ToDoDecorator import update_main_task_focus_time


class TodoLogService:
    @staticmethod
    @update_main_task_focus_time
    def create_todo_log(todo_log_dict):
        """
        创建Todo日志（包含业务校验）
        :param todo_log_dict: 日志信息字典，必填键：user_id、task_id、description、self_score
        :return: (bool, result)
            成功：(True, 创建的日志字典)
            失败：(False, 错误信息)
        """
        # 1. 业务参数校验
        try:
            # 校验必填字段
            required_fields = ['user_id', 'task_id', 'description', 'self_score']
            for field in required_fields:
                if field not in todo_log_dict or not todo_log_dict[field]:
                    return False, f"参数错误：缺少必填字段'{field}'或字段值为空"

            # 校验数据格式
            user_id = todo_log_dict['user_id']
            task_id = todo_log_dict['task_id']
            self_score = todo_log_dict['self_score']
            focus_time = todo_log_dict.get('focus_time', 0)

            if not isinstance(user_id, int) or user_id <= 0:
                return False, "参数错误：user_id必须为正整数"
            if not isinstance(task_id, int) or task_id <= 0:
                return False, "参数错误：task_id必须为正整数"
            if not isinstance(self_score, int) or self_score < 0 or self_score > 100:
                return False, "参数错误：self_score必须为0-100的整数"
            if not isinstance(focus_time, int) or focus_time < 0:
                return False, "参数错误：focus_time必须为非负整数"

            # 校验字符串长度
            log_title = todo_log_dict.get('log_title', '')
            description = todo_log_dict['description']
            if len(log_title) > 100:
                return False, "参数错误：log_title长度不能超过100个字符"
            if len(description) == 0:
                return False, "参数错误：description不能为空"

        except Exception as e:
            return False, f"参数校验失败：{str(e)}"
        print(todo_log_dict)

        # 2. 调用DAO层创建数据
        success, result = TodoLogDAO.create_todo_log(todo_log_dict)
        if not success:
            return False, result

        # 3. 格式化返回结果（将对象转为字典，便于接口返回）
        log_dict = {
            'id': result.id,
            'user_id': result.user_id,
            'task_id': result.task_id,
            'log_title': result.log_title,
            'description': result.description,
            'self_score': result.self_score,
            'focus_time': result.focus_time,
            'submit_time': result.submit_time.strftime('%Y-%m-%d %H:%M:%S') if result.submit_time else None
        }
        return True, log_dict

    @staticmethod
    def get_todo_log_by_id(log_id):
        """
        根据日志ID查询单条日志
        :param log_id: 日志主键ID
        :return: (bool, result)
            成功（存在）：(True, 日志字典)
            成功（不存在）：(True, None)
            失败：(False, 错误信息)
        """
        # 1. 校验参数
        if not isinstance(log_id, int) or log_id <= 0:
            return False, "参数错误：log_id必须为正整数"

        # 2. 调用DAO层查询
        success, result = TodoLogDAO.get_todo_log_by_id(log_id)
        if not success:
            return False, result

        # 3. 格式化结果
        if result:
            log_dict = {
                'id': result.id,
                'user_id': result.user_id,
                'task_id': result.task_id,
                'log_title': result.log_title,
                'description': result.description,
                'self_score': result.self_score,
                'focus_time': result.focus_time,
                'submit_time': result.submit_time.strftime('%Y-%m-%d %H:%M:%S') if result.submit_time else None
            }
            return True, log_dict
        return True, None

    @staticmethod
    def get_todo_logs_by_condition(**kwargs):
        """
        根据条件查询日志列表（支持分页、多条件组合）
        :param kwargs: 查询条件，可选键：
            - user_id: 用户ID（必填）
            - task_id: 主任务ID
            - self_score: 自我评分
            - submit_time_start: 提交时间起始（字符串格式：%Y-%m-%d %H:%M:%S）
            - submit_time_end: 提交时间结束（字符串格式：%Y-%m-%d %H:%M:%S）
            - page: 页码（默认1）
            - per_page: 每页条数（默认20）
        :return: (bool, result)
            成功：(True, 分页结果字典)
            失败：(False, 错误信息)
        """
        # 1. 业务参数校验
        try:
            # 校验必填条件（user_id为必填，确保数据隔离）
            if 'user_id' not in kwargs or not kwargs['user_id']:
                return False, "参数错误：缺少必填字段'user_id'"
            if not isinstance(kwargs['user_id'], int) or kwargs['user_id'] <= 0:
                return False, "参数错误：user_id必须为正整数"

            # 校验可选参数格式
            query_params = {}

            # 处理user_id（必传）
            query_params['user_id'] = kwargs['user_id']

            # 处理task_id
            if 'task_id' in kwargs and kwargs['task_id'] is not None:
                if not isinstance(kwargs['task_id'], int) or kwargs['task_id'] <= 0:
                    return False, "参数错误：task_id必须为正整数"
                query_params['task_id'] = kwargs['task_id']

            # 处理self_score
            if 'self_score' in kwargs and kwargs['self_score'] is not None:
                if not isinstance(kwargs['self_score'], int) or kwargs['self_score'] < 0 or kwargs['self_score'] > 100:
                    return False, "参数错误：self_score必须为0-100的整数"
                query_params['self_score'] = kwargs['self_score']

            # 处理时间范围（字符串转datetime）
            time_pattern = r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$'
            if 'submit_time_start' in kwargs and kwargs['submit_time_start']:
                if not re.match(time_pattern, kwargs['submit_time_start']):
                    return False, "参数错误：submit_time_start格式应为'YYYY-MM-DD HH:MM:SS'"
                query_params['submit_time_start'] = datetime.strptime(kwargs['submit_time_start'], '%Y-%m-%d %H:%M:%S')

            if 'submit_time_end' in kwargs and kwargs['submit_time_end']:
                if not re.match(time_pattern, kwargs['submit_time_end']):
                    return False, "参数错误：submit_time_end格式应为'YYYY-MM-DD HH:MM:SS'"
                query_params['submit_time_end'] = datetime.strptime(kwargs['submit_time_end'], '%Y-%m-%d %H:%M:%S')

            # 处理分页参数
            page = kwargs.get('page', 1)
            per_page = kwargs.get('per_page', 30)
            if not isinstance(page, int) or page < 1:
                return False, "参数错误：page必须为正整数"
            if not isinstance(per_page, int) or per_page < 1 or per_page > 100:
                return False, "参数错误：per_page必须为1-100的整数"
            query_params['page'] = page
            query_params['per_page'] = per_page

        except Exception as e:
            return False, f"参数校验失败：{str(e)}"

        # 2. 调用DAO层查询分页数据
        success, pagination = TodoLogDAO.get_todo_logs_by_condition(**query_params)
        if not success:
            return False, pagination

        # 3. 格式化分页结果
        log_list = []
        for log in pagination.items:
            log_list.append({
                'id': log.id,
                'user_id': log.user_id,
                'task_id': log.task_id,
                'log_title': log.log_title,
                'description': log.description,
                'self_score': log.self_score,
                'focus_time': log.focus_time,
                'submit_time': log.submit_time.strftime('%Y-%m-%d %H:%M:%S') if log.submit_time else None
            })

        result_dict = {
            'total': pagination.total,  # 总记录数
            'page': pagination.page,  # 当前页码
            'per_page': pagination.per_page,  # 每页条数
            'pages': pagination.pages,  # 总页数
            'has_next': pagination.has_next,  # 是否有下一页
            'has_prev': pagination.has_prev,  # 是否有上一页
            'items': log_list  # 当前页数据列表
        }
        return True, result_dict

    @staticmethod
    @update_main_task_focus_time
    def update_todo_log(log_id, update_dict, operator_user_id):
        """
        更新日志信息（包含权限校验和数据校验）
        :param log_id: 要更新的日志ID
        :param update_dict: 要更新的字段字典
        :param operator_user_id: 操作人用户ID（用于权限校验）
        :return: (bool, result)
            成功（存在并更新）：(True, 更新后的日志字典)
            成功（不存在）：(True, None)
            失败：(False, 错误信息)
        """
        # 1. 基础参数校验
        if not isinstance(log_id, int) or log_id <= 0:
            return False, "参数错误：log_id必须为正整数"
        if not isinstance(operator_user_id, int) or operator_user_id <= 0:
            return False, "参数错误：operator_user_id必须为正整数"
        if not update_dict or not isinstance(update_dict, dict):
            return False, "参数错误：update_dict不能为空且必须为字典"


        # 3. 校验更新字段的数据格式
        try:
            if 'self_score' in update_dict:
                self_score = update_dict['self_score']
                if not isinstance(self_score, int) or self_score < 0 or self_score > 100:
                    return False, "参数错误：self_score必须为0-100的整数"

            if 'focus_time' in update_dict:
                focus_time = update_dict['focus_time']
                if not isinstance(focus_time, int) or focus_time < 0:
                    return False, "参数错误：focus_time必须为非负整数"

            if 'log_title' in update_dict:
                log_title = update_dict['log_title']
                if len(log_title) > 100:
                    return False, "参数错误：log_title长度不能超过100个字符"

            if 'description' in update_dict:
                description = update_dict['description']
                if len(description) == 0:
                    return False, "参数错误：description不能为空"
        except Exception as e:
            return False, f"参数校验失败：{str(e)}"

        # 4. 权限校验：只能更新自己的日志
        success, log = TodoLogDAO.get_todo_log_by_id(log_id)
        if not success:
            return False, log
        if not log:
            return True, None  # 日志不存在，返回成功+None
        if log.user_id != operator_user_id:
            return False, "权限错误：只能更新自己创建的日志"

        # 5. 调用DAO层执行更新
        success, updated_log = TodoLogDAO.update_todo_log(log_id, update_dict)
        if not success:
            return False, updated_log

        # 6. 格式化返回结果
        if updated_log:
            log_dict = {
                'id': updated_log.id,
                'user_id': updated_log.user_id,
                'task_id': updated_log.task_id,
                'log_title': updated_log.log_title,
                'description': updated_log.description,
                'self_score': updated_log.self_score,
                'focus_time': updated_log.focus_time,
                'submit_time': updated_log.submit_time.strftime(
                    '%Y-%m-%d %H:%M:%S') if updated_log.submit_time else None
            }
            return True, log_dict
        return True, None

    @staticmethod
    @update_main_task_focus_time
    def delete_todo_log(log_id, operator_user_id):
        """
        删除日志（包含权限校验）
        :param log_id: 要删除的日志ID
        :param operator_user_id: 操作人用户ID（用于权限校验）
        :return: (bool, result)
            成功：(True, None)
            失败：(False, 错误信息)
        """
        # 1. 基础参数校验
        if not isinstance(log_id, int) or log_id <= 0:
            return False, "参数错误：log_id必须为正整数"
        if not isinstance(operator_user_id, int) or operator_user_id <= 0:
            return False, "参数错误：operator_user_id必须为正整数"

        # 2. 权限校验：只能删除自己的日志
        success, log = TodoLogDAO.get_todo_log_by_id(log_id)
        if not success:
            return False, log
        if log and log.user_id != operator_user_id:
            return False, "权限错误：只能删除自己创建的日志"

        # 3. 调用DAO层执行删除
        success, result = TodoLogDAO.delete_todo_log(log_id)
        if not success:
            return False, result
        return True, {'task_id': log.task_id,
                      'log_id': log.id, }

    @staticmethod
    def batch_delete_todo_logs_by_task_id(task_id, operator_user_id):
        """
        根据主任务ID批量删除关联日志（包含权限校验，用于主任务删除时的级联操作）
        :param task_id: 主任务ID
        :param operator_user_id: 操作人用户ID（用于权限校验）
        :return: (bool, result)
            成功：(True, 删除的记录数)
            失败：(False, 错误信息)
        """
        # 1. 基础参数校验
        if not isinstance(task_id, int) or task_id <= 0:
            return False, "参数错误：task_id必须为正整数"
        if not isinstance(operator_user_id, int) or operator_user_id <= 0:
            return False, "参数错误：operator_user_id必须为正整数"

        # 2. 权限校验：只能删除自己任务下的日志
        # 先查询该任务下是否有日志，且日志的user_id是否与操作人一致
        success, pagination = TodoLogDAO.get_todo_logs_by_condition(
            task_id=task_id,
            user_id=operator_user_id,
            page=1,
            per_page=1
        )
        if not success:
            return False, pagination
        # 若存在该用户下的该任务日志，则允许删除；若不存在，也允许执行（避免误删他人数据）
        # 实际删除时会自动过滤user_id，确保只删除自己的日志
        success, delete_count = TodoLogDAO.delete_todo_logs_by_task_id(task_id)
        if not success:
            return False, delete_count

        return True, delete_count
